package Markers;


import interfaces.IMap;

import java.awt.Point;
import java.util.ArrayList;


public class RoundContourSelector implements IContourSelector
{
	ArrayList<IContour> Contours;
	int XOffset[];
	int YOffset[];
	int Invert = 1;
	IMap AllContoursMap;
	
	//===========================================================================
	public RoundContourSelector()
	{
		XOffset = new int[8];
		YOffset = new int[8];
		XOffset[0]=-1;
		YOffset[0]=0;
		
		XOffset[1]=-1;
		YOffset[1]=+1;
		
		XOffset[2]=0;
		YOffset[2]=+1;
		
		XOffset[3]=+1;
		YOffset[3]=+1;
		
		XOffset[4]=+1;
		YOffset[4]=0;
		
		XOffset[5]=+1;
		YOffset[5]=-1;
		
		XOffset[6]=0;
		YOffset[6]=-1;
		
		XOffset[7]=-1;
		YOffset[7]=-1;		
	}
	//===========================================================================
	@Override
	public ArrayList<IContour> Select(IMap map) 
	{
		Contours = new ArrayList<IContour>();	
		AllContoursMap = new BinMap(map.Height(),map.Width());
		for (int y = 0; y < map.Height(); y++)
		{
            for (int x = 0; x < map.Width(); x++)
            {            	
            	int cur = map.Get(x, y);
            	if(IsBorder(map, y, x, cur))            	        		
	        		if(!InContours(x, y))
	        		{
	        			IContour C = CreateCotour(map,x, y);
	        			if(C!=null && C.Count()>25)
	        				Contours.add(C );   
	        		}            	
            }           
		}
		
		return Contours;
	}
	//===========================================================================
	private boolean InContours( int x, int y)
	{
		return AllContoursMap.Get(x, y)>0;
		/*for (IContour oContour : Contours)
			if( oContour.InContour(x, y))
				return true;
		
		return false;	*/
	}
	//===========================================================================
	private boolean IsBorder(IMap map, int y, int x, int cur) 
	{
		return  (cur == 255) && ( cur != map.Get(x-1, y) );
	}
	//===========================================================================
	private IContour CreateCotour(IMap map, int x, int y) 
	{
		IContour oContour = newIContour();
		Invert = 1;	
		boolean IsCircle = false;
		int LastPointIndex=0;
		Point curPoint = new Point(x,y);
		
		while (!IsCircle) 
		{
			curPoint = FindPoint(map,oContour,curPoint.x,curPoint.y);
			
			if(curPoint == null)
			{
				curPoint = oContour.GetPoint(oContour.Count() - 1 - LastPointIndex);				
				LastPointIndex++;	
				if(curPoint==null)
				{
					IsCircle = true;
					LastPointIndex = 0;	
				}
			}
			else 
			{				
				LastPointIndex = 0;								
			}
			
			if(curPoint==null || curPoint.x==x && curPoint.y==y)
				IsCircle = true;			
		}	
		
		return oContour;
	}
	//===========================================================================
	private Point FindPoint(IMap map,IContour oContour,int X,int Y)
	{
		int nX = X+XOffset[7]*Invert;
		int nY = Y+YOffset[7]*Invert;
		boolean isCurFill = IsContour(map.Get(nX, nY));
		return recursFind(map,oContour,X,Y,0,isCurFill);
		/*for (int i = 0; i < XOffset.length; i++) 
		{				
			int nX = X+XOffset[i]*Invert;
			int nY = Y+YOffset[i]*Invert;
			if(IsContour(map.Get(nX, nY)) && !oContour.InContour(nX, nY))
			{
				if(i>5)
					Invert *=-1;			
				
				oContour.AddPoint(nX, nY);
				
				return new Point(nX,nY);
			}				
		}*/
		//return null;
	} 
	//===========================================================================
	Point recursFind(IMap map, IContour oContour,int X,int Y,int index,boolean isLastFill)
	{
		if(index == 8)
			return null;
		int nX = X+XOffset[index]*Invert;
		int nY = Y+YOffset[index]*Invert;
		boolean isCurFill = IsContour(map.Get(nX, nY));
		if(isCurFill && !isLastFill && !InContours(nX, nY))
		{
			if(index>5)
				Invert *=-1;		
			AllContoursMap.Set(nX, nY, 255);
			oContour.AddPoint(nX,nY);
			return new Point(nX,nY);
		}
		return recursFind(map,oContour,X,Y,index+1,isCurFill);
	}
	//===========================================================================
	private boolean IsContour(int cur) 
	{		
		return cur==255;
	}
	//===========================================================================
	private IContour newIContour() 
	{
		return new PointContour();
	}
}
